package com.ruoyi.mtg.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONReader;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.mtg.domain.CardData;
import com.ruoyi.mtg.mapper.CardDataMapper;
import com.ruoyi.mtg.service.IMtgService;
import com.ruoyi.mtg.utils.MtgUtil;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MtgServiceImpl implements IMtgService {

    @Autowired
    CardDataMapper cardDataMapper;

    ExecutorService es = Executors.newScheduledThreadPool(5);

    @SneakyThrows
    @Override
    public List<CardData> readJsonAllCards(String filePath, boolean save2db) {
        File file = new File(filePath);
        if (!file.exists() || file.isDirectory()) {
            throw new RuntimeException("invalid json file! filePath = " + filePath);
        }


        Set<String> dbCards = cardDataMapper.selectList(new QueryWrapper<>())
                .stream().map(CardData::getName).collect(Collectors.toSet());
        log.debug("dbCards.size = {}", dbCards);

        List<CardData> cards = new ArrayList<>();


        @Cleanup FileReader fr = new FileReader(file);
        @Cleanup JSONReader reader = new JSONReader(fr);
        reader.startObject();
        while (reader.hasNext()) {
            String key = reader.readString();  // card name
            String val = reader.readString();
            log.debug("=== key: {} ===", key);
            if (dbCards.contains(key)) {
                log.debug("card in db: {}", key);
                continue;
            }

            JSONObject jo = JSONObject.parseObject(val);
            String name = jo.getString("name");
            String uuid = jo.getString("uuid");
            String type = jo.getString("type");
            String colors = jo.getJSONArray("colors").stream().map(o -> (String) o).collect(Collectors.joining(","));
            String manaCost = jo.getString("manaCost");
            BigDecimal convertedManaCost = BigDecimal.valueOf(jo.getDouble("convertedManaCost")).setScale(1, RoundingMode.HALF_UP);
            String printings = jo.getJSONArray("printings").stream().map(o -> (String) o).collect(Collectors.joining(","));
            String text = jo.getString("text");
            String scryfallOracleId = jo.getString("scryfallOracleId"); // https://scryfall.com/
            String power = jo.getString("power");
            String toughness = jo.getString("toughness");

            CardData cardData = new CardData().setName(name)
                    .setUuid(uuid)
                    .setType(type)
                    .setColors(colors)
                    .setManaCost(manaCost)
                    .setConvertedManaCost(convertedManaCost)
                    .setPrintings(printings)
                    .setText(text)
                    .setScryfallOracleId(scryfallOracleId)
                    .setPower(power)
                    .setToughness(toughness);
            JSONArray foreignData = jo.getJSONArray("foreignData");
            if (null != foreignData && foreignData.size() > 0) {
                foreignData.stream()
                        .map(o -> (JSONObject) o)
                        .filter(o -> "Chinese Simplified".equals(o.getString("language")))
                        .findFirst()
                        .ifPresent(o -> {
                            String nameCn = o.getString("name");
                            String typeCn = o.getString("type");
                            String textCn = o.getString("text");
                            cardData.setNameCn(nameCn)
                                    .setTypeCn(typeCn)
                                    .setTextCn(textCn);
                        });
            }
            if (StrUtil.isEmpty(cardData.getNameCn())) {
                CardData cnData = MtgUtil.queryCardFromIyingdi(cardData.getName());
                if (null != cnData) {
                    cardData.setNameCn(cnData.getNameCn());
                    cardData.setTypeCn(cnData.getTypeCn());
                    cardData.setTextCn(cnData.getTextCn());
                }
            }

            cards.add(cardData);
            log.debug("carddata: name = {}, nameCn = {}", cardData.getName(), cardData.getNameCn());
            if (save2db) {
                es.submit(() -> {
                    cardDataMapper.insert(cardData);
                });
            }
        }
        reader.endObject();
        return cards;
    }
}
